package com.instpower.things.handlers;

import com.alibaba.fastjson.JSONObject;
import com.instpower.things.config.Configs;
import com.instpower.things.entity.CabinetCacheVO;
import com.instpower.things.instpower.Connection;
import com.instpower.things.instpower.Handler;
import com.instpower.things.service.MessageService;
import com.instpower.things.transport.*;
import com.instpower.things.util.CabinetQueryUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName Handler09D9Action
 * @Author: hellmash@gmail.com
 * @Date: 2020/3/18
 * @Version: 1.0.0
 * @Description: 交易
 */
@Component(value = "CMD09D9")
public class Handler09D9Action extends Handler<Request> {

    /**
     * 回复确认报文长度
     */
    private final static int RTNDATA_LEN        = 8;

    @Autowired
    private MessageService messageService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public short getId() {
        return Configs.ORDER;
    }

    @Override
    public void execute(Connection connection, Request request) throws UnsupportedEncodingException {
        String sn = request.getHeader().getAddr();
        logger.info("[{}]:Exec - CMD09D9 - BEGIN",sn);
        DataBuffer buffer = request.getData().encode();

        byte cmd        = buffer.readByte();
        int orderNo = buffer.readInt();
        byte slotNum    = buffer.readByte();
        byte rentOrder = buffer.readByte();

        String bsnKey = String.format(Configs.PREFIX_BSN, request.getHeader().getAddr(), orderNo);

        //删除临时缓存
        String finishKey = String.format(Configs.RENT_08F6_FINISH, Integer.toString(orderNo));
        //超过08F6发送的轮询间隔时间
        redisTemplate.opsForValue().set(finishKey, "1", 20, TimeUnit.SECONDS);
        String cacheOrderNo = String.format(Configs.ANKER_RENT_RETURN_ORDER_NO, (sn + slotNum));
        String orderNoCache = redisTemplate.opsForValue().get(cacheOrderNo);

        //电池归还 -- 只有0x01
        if(0x01 == cmd) {
            String bsn = buffer.readString(16);
            logger.info("09d9 0x01 == cmd 的时候,电池sn:{}",bsn);
            Response response = new Response();
            Header header = new Header();
            header.setSyn(request.getHeader().getSyn());
            header.setRes(request.getHeader().getRes());
            header.setAddr(request.getHeader().getAddr());
            header.setPtrol(request.getHeader().getPtrol());
            header.setCommand(request.getHeader().getCommand());
            header.setLength((short)(RTNDATA_LEN + 2));
            response.setHeader(header);
            MTData mData = new MTData();
            DataBuffer rtnBuffer = new DataBuffer(RTNDATA_LEN);
            rtnBuffer.writeByte(0x02);
            rtnBuffer.writeInt(orderNo);
            rtnBuffer.writeByte(slotNum);
            rtnBuffer.writeByte(rentOrder);
            //0x00成功，0x01失败,需要具体业务做判断
            rtnBuffer.writeByte(0x00);
            mData.decode(rtnBuffer);
            response.setData(mData);
            //设置交易中的电池SN,20秒周期自动删除
            redisTemplate.opsForValue().set(bsnKey, bsn,60, TimeUnit.SECONDS);
            String batteryCache = redisTemplate.opsForValue().get(bsnKey);
            logger.info("09d9 0x01 == cmd 的时候,从redis取出电池,key:{},sn:{}",bsnKey,batteryCache);
            this.sendResponse(connection, response);
            logger.info("回复0x02交易指令");
            // 租借成功--目前只有0x03,没有0x01
        }else if(0x03 == cmd){
            //删除缓存，确认已经正常完成交易
            redisTemplate.delete(String.format(Configs.RENT_ORDER_KEY_PREF, Integer.toString(orderNo)));
            short result = buffer.readUnsignByte();
            String bsn = redisTemplate.opsForValue().get(bsnKey);
            logger.info("09d9 0x03 == cmd 的时候,从redis取出电池,key:{},sn:{}",bsnKey,bsn);
            //正常弹出，状态为0
            int status;
            if(0 == result || 0xa3 == result){
                status = 0;
                //借还成功以后，要求设备立马上报最新的机柜状态
                connection.getmContext().channel().eventLoop().schedule(()-> CabinetQueryUtil.cabinetQuery(sn),10L, TimeUnit.SECONDS);
//                CabinetQueryUtil.cabinetQuery(sn);
            }else{
                status = 99;
            }
            //增加了一个强制弹出的结果处理
            boolean isReturn = true;
            if(0x00 == rentOrder || 0x02 == rentOrder) {
                isReturn = false;
            }else {
                //正常归还电池删除redis中正在租借中的电池sn
                checkRentingBatteryHash(request.getHeader().getAddr(), bsn);
            }
            String cabinetSn = request.getHeader().getAddr();
            if (StringUtils.isEmpty(bsn)){
                bsn = getBatterySn(cabinetSn,(int)slotNum);
            }
            logger.info("09d9 发送mq消息:cabinetSn:{},batterySn:{},slotNum:{},orderNO:{},requestType:{},status:{}",cabinetSn,bsn,slotNum,orderNoCache,rentOrder,status);
            messageService.send(cabinetSn,bsn,isReturn,slotNum,orderNoCache,rentOrder,status,Integer.toHexString(result));
            logger.info("[{}]:交易处理完成",sn);
        }
        //release after read
        buffer.release();
        logger.info("[{}]:Exec - CMD09D9 - END",sn);
        //发送机柜信息查询命令
//        CabinetQueryUtil.cabinetQuery(sn);
    }

    /**
     * 归还电池检测 renting_battery_hash内是否存在有租借中的订单
     * @param batterySn
     */
    public void checkRentingBatteryHash(String cabinetSn,String batterySn){
        if (batterySn == null){
            logger.info("[renting_battery_hash]:Cabinet:[{}],battery sn:{}",cabinetSn,batterySn);
            return;
        }
        String rentingBatteryHash = "renting_battery_hash";
        boolean isExist = redisTemplate.opsForHash().hasKey(rentingBatteryHash,batterySn);
        if (isExist){
            logger.info("cabinetSn:{} batterySn:{} is exist renting order",cabinetSn,batterySn);
            redisTemplate.opsForHash().delete(rentingBatteryHash,batterySn);
        }

    }

    /**
     * 获取机柜缓存
     * @param cabinetSn
     * @return
     */
    public CabinetCacheVO getCabinetCache(String cabinetSn) {
        String cabinetInfo = (String) redisTemplate.opsForValue().get(cabinetSn);
        logger.info("从redis取机柜数据,cabinetSn:{},值:{}",cabinetSn,cabinetInfo);
        if (null != cabinetInfo && !"".equals(cabinetInfo)) {
            return JSONObject.parseObject(cabinetInfo, CabinetCacheVO.class);
        }
        return null;
    }

    /**
     * 获取电池SN
     * @param cabinetSn
     * @param slotNum
     * @return
     */
    public String getBatterySn(String cabinetSn,Integer slotNum) {
        CabinetCacheVO cabinetCacheVO = this.getCabinetCache(cabinetSn);
        if (null == cabinetCacheVO) {
            logger.error("机柜[{}]心跳信息不存在", cabinetSn);
        }
        List<CabinetCacheVO.SlotInfoBean> slotInfos = cabinetCacheVO.getSlot_info();
        for (CabinetCacheVO.SlotInfoBean slot: slotInfos) {
            if (slotNum == slot.getSlot_num()){
                return slot.getBattery_sn();
            }
        }
        return null;
    }

}
